Programas/atividades desenvolvidas para a disciplina DCA0445 - Processamento Digital de Imagens, do curso de Engenharia de Computação da Universidade Federal do Rio grande do Norte UFRN
Prefácio
C++ utilizando-se da biblioteca OpenCV
e em ambiente Linux. Para compilar qualquer programa presente neste documento, pode-se fazer uso deste Makefile, coloca o Makefile na mesma pasta do
código fonte, extensão .cpp, e execute via terminal o comando
make <nome_do_programa>. Todos os códigos encontram-se no Repositório do github.
1. Programa Region
Este programa consiste em negativar uma certa região dentro de uma imagem, delimitada por um retângulo informado pelo usuário. o programa varre a área correspondente na imagem e troca os valores dos pixels para seus inversos, ou seja 255 - valor_atual.
Compilando e Executando.
$ make region $ ./region <caminho_para_a_imagem>
O código fonte completo se encontra aqui region.cpp.
void region(Mat &img, CvPoint *p){
for(unsigned int i = p[0].x; i < p[1].x; i++)
for(unsigned int j = p[0].y; j < p[1].y; j++)
img.at<uint8_t>(i,j) = 255 - img.at<uint8_t>(i,j);
}
2. Troca Regiões
O usuário deve passar uma imagem qualquer, e o programa passara para escala de cinza e particionara a imagem em 4(quatro) partes simétricas e realizara a troca na diagonal dessas quatro subimagens.
Para este programa uma imagem foi pensada sendo composta por 4 regiões da seguinte forma:
A |
|
C |
|
Compilando e Executando.
$ make trocaregioes $ ./trocaregioes <caminho_para_a_imagem>
Código completo em trocaregioes.cpp
{
w = img.size().width;
h = img.size().height;
result = img.clone();
img(cv::Rect(0,0, w/2, h/2)).copyTo(result(cv::Rect((w-1)/2, (h-1)/2, w/2, h/2))); (1)
img(cv::Rect((w-1)/2, 0, w/2, h/2)).copyTo(result(cv::Rect(0, (h-1)/2, w/2, h/2))); (2)
img(cv::Rect(0, (h-1)/2, w/2, h/2)).copyTo(result(cv::Rect((w-1)/2, 0, w/2, h/2))); (3)
img(cv::Rect((w-1)/2, (h-1)/2, w/2, h/2)).copyTo(result(cv::Rect(0, 0, w/2, h/2))); (4)
}
| 1 | Sobrepoe A da img original em D de result |
| 2 | Sobrepoe B da img original em C de result |
| 3 | Sobrepoe C da img original em B de result |
| 4 | Sobrepoe D da img original em A de result |
Resultado
D |
|
B |
|
3. Conta Bolhas
Este programa consiste em contar o número de regiões brancas puras, com e sem "buracos", o fundo da imagem deve ser puramente preto e os objetos puramente brancos, o programa foi testado utilizando a imagem bolhas.png. Mas o mesmo deve funcionar para qualquer imagem que siga o padrão especificado a cima.
O algoritmo consiste em 4 passos bem definidos. O código completo se encontra neste link: contaregioes.cpp.
3.1. Passo 1- Remover objetos das bordas
//remove da borda superior e inferior
for(int i = 0; i < width; i++){
if(image.at<uint8_t>(0, i) == OBJ_COLOR)
floodFill(image, CvPoint(i, 0), BACK_COLOR);
if(image.at<uint8_t>(height-1,i) == OBJ_COLOR)
floodFill(image, CvPoint(i, height-1), BACK_COLOR);
}
//remove das laterais
for(int i = 0; i < height; i++){
//lateral esquerda
if(image.at<uint8_t>(i, 0) == OBJ_COLOR)
floodFill(image, CvPoint(0, i), BACK_COLOR);
//lateral direita
if(image.at<uint8_t>(i, width-1) == OBJ_COLOR)
floodFill(image, CvPoint(width-1, i), BACK_COLOR);
}
3.2. Passo 2- Contar bolhas com buraco
//troca o background, para facilitar a identificar os buracos das bolhas
floodFill(image, CvPoint(0,0), NEW_BACK_COLOR);
for(int i = 0; i < height; i++)
for(int j = 0; j < width; j++)
{
//identifica uma bolha com buraco
if(image.at<uint8_t>(i,j) == BACK_COLOR && image.at<uint8_t>(i,j-1) == OBJ_COLOR){
//soma um no numero de bolhas e "apaga" a bolha encontrada
nbolhas_com_buracos++;
floodFill(image, CvPoint(j-1, i), NEW_BACK_COLOR);
}
}
3.3. Passo 3- Contar bolhas sem buracos
//conta bolhas sem buracos
for(int i = 0; i < height; i++)
for(int j = 0; j < width; j++)
{
//identifica uma bola
if(image.at<uint8_t>(i,j) == OBJ_COLOR){
//soma um no numero de bolhas e "apaga" a bolha encontrada
nbolhas_sem_buracos++;
floodFill(image, CvPoint(j, i), NEW_BACK_COLOR);
}
}
3.4. Resultado
4. Histograma
4.1. Equalize
Implementação de um Equalizador de Histograma para imagens em tons de cinza.
Algoritmo de equalização (imagens em tons de cinza) utilizado:
-
Calcular Histograma: \(h(r_k), k \in [0,255\)];
-
Calcular Histograma Acumulado: \(ha(r_k) = \sum{h(r_j)}, j \in [0,255\)];
-
Normalizar o Histograma Acumulado, na faixa de [0, 255]: \(ha(r_k) = ha(r_k)/ha(r_255)\);
-
Transformar a imagem: \(f(x,y) = ha(f(x,y))\).
#include <iostream>
#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;
int main(int argc, char** argv){
Mat frame;
Mat hist;
VideoCapture cap;
uint8_t histEq[256];
int histsize = 256;
int sum;
float range[] = {0, 256};
const float *histrange = { range };
cap.open(0);
if(!cap.isOpened()){
cout << "cameras indisponiveis\n";
return -1;
}
std::cout << "Pressione qualquer tecla para encerrar o programa." << '\n';
while(1){
cap >> frame;
cvtColor(frame, frame, CV_BGR2GRAY);
imshow("Original", frame);
//Calculo do histograma
calcHist(&frame, 1, 0, Mat(), hist, 1, &histsize, &histrange);
/*calculo do histograma acumulado */
/*e normalizacao do histograma acumulado*/
/**
* Calcula o vetor que ira realizar a transformacao nos valores dos pixels
*/
sum = 0;
for(int i = 0; i < histsize; i++)
{
sum+= hist.at<float>(i);
histEq[i] = sum*255.0/frame.total();
}
//substituicao dos valores dos pixels
for(int i = 0; i < frame.size().height; i++)
for(int j = 0; j < frame.size().width; j++)
frame.at<uint8_t>(i,j) = histEq[frame.at<uint8_t>(i,j)];
imshow("Equalizado", frame);
if(waitKey(10) != 255)break;
}
return 0;
}
Antes e Depois da equalização do histograma.
Código completo: equalize.cpp
4.2. Motiondetector
Utilizando comparação de histogramas entre frames consecutivos, comparando-o por calculo da correlação(usando função do OpenCV, compareHist), para identificar ocorrência de movimento, para isso foi estabelecido, de forma empírica, um limiar para a correlação, ao se identificar um valor de correlação abaixo do limiar, um circulo verde é desenhado no canto superior direito da imagem, indicando uma detecção de movimento.
Makefile utilizado para compilar o programa motiondetector, é diferente pois inclui a capacidade de gerar gifs.